/** \file    merge.h
  * \brief   Performs pasting of overlay image onto background with various alpha operations.
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/merge.h,v 1.2 2004/06/17 17:58:41 cscom1r4 Exp $
  */

#ifndef _merge_h_
#define _merge_h_

#include "color.h"

namespace img {

template <class T, bool Inv>
struct copy_alpha; 

template <>
struct copy_alpha< BGRA<unsigned char>, false > {
	typedef BGRA<unsigned char> value_type;
	void operator() (value_type & dst, const value_type & src) const {
		dst.a = src.a;
	}
};

template <>
struct copy_alpha< BGRA<unsigned char>, true > {
	typedef BGRA<unsigned char> value_type;
	void operator() (value_type & dst, const value_type & src) const {
		dst.a = 255 - src.a;
	}
};
//
// 4 blending class-functions to use with
//	template <class R1, class R2, class Op>
//	void transform(R1 & r1, const size_rect & where,
//		const R2 & r2, const size_point & from, Op & op)
//
// alpha_blend
// inv_alpha_blend
// premul_alpha_blend
// inv_premul_alpha_blend
//

template <class T, bool InvCopyAlpha = false>
struct alpha_blend; 

template <bool InvCopyAlpha>
struct alpha_blend< BGRA<unsigned char>, InvCopyAlpha > {
	typedef BGRA<unsigned char> value_type;
	void operator() (value_type & dst, const value_type & src) const {
		dst.b = (dst.b * (255 - src.a) + src.b * src.a) / 255;
		dst.g = (dst.g * (255 - src.a) + src.g * src.a) / 255;
		dst.r = (dst.r * (255 - src.a) + src.r * src.a) / 255;
		copy_alpha<value_type, InvCopyAlpha>()(dst, src);
	}
};

template <class T, bool InvCopyAlpha = true>
struct inv_alpha_blend; 

template <bool InvCopyAlpha>
struct inv_alpha_blend< BGRA<unsigned char>, InvCopyAlpha > {
	typedef BGRA<unsigned char> value_type;
	void operator() (value_type & dst, const value_type & src) const {
		dst.b = (dst.b * src.a + src.b * (255 - src.a)) / 255;
		dst.g = (dst.g * src.a + src.g * (255 - src.a)) / 255;
		dst.r = (dst.r * src.a + src.r * (255 - src.a)) / 255;
		copy_alpha<value_type, InvCopyAlpha>()(dst, src);
	}
};

template <class T, bool InvCopyAlpha = false>
struct premul_alpha_blend; 

inline int lim255(int x) {
	return x > 255 ? 255 : x;
}

template <bool InvCopyAlpha>
struct premul_alpha_blend< BGRA<unsigned char>, InvCopyAlpha > {
	typedef BGRA<unsigned char> value_type;
	void operator() (value_type & dst, const value_type & src) const {
		dst.b = lim255((dst.b * (255 - src.a) + src.b * 255) / 255);
		dst.g = lim255((dst.g * (255 - src.a) + src.g * 255) / 255);
		dst.r = lim255((dst.r * (255 - src.a) + src.r * 255) / 255);
		copy_alpha<value_type, InvCopyAlpha>()(dst, src);
	}
};

template <class T, bool InvCopyAlpha = true>
struct inv_premul_alpha_blend; 

template <bool InvCopyAlpha>
struct inv_premul_alpha_blend< BGRA<unsigned char>, InvCopyAlpha > {
	typedef BGRA<unsigned char> value_type;
	void operator() (value_type & dst, const value_type & src) const {
		dst.b = lim255((dst.b * src.a + src.b * 255) / 255);
		dst.g = lim255((dst.g * src.a + src.g * 255) / 255);
		dst.r = lim255((dst.r * src.a + src.r * 255) / 255);
		copy_alpha<value_type, InvCopyAlpha>()(dst, src);
	}
};

} //namespace img

#endif //_merge_h_
